/**<P>Title:ucweb</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2010</p>
 *<p>Company: ucweb.com</p>
 *@author chensl@ucweb.com
 *@version 
 */
package com.ucweb.pooltest.pool.base;

import java.lang.ref.WeakReference;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Queue;

import android.util.Log;

/**
 * @author chensl@ucweb.com
 * 
 *         上午10:20:56 2014-8-28
 */
public abstract class BaseObjectPool<T> implements IObjectPool<T> {
	private final String TAG = getClass().getSimpleName();
	private final boolean DEBUG = false;
	protected static int sMaxObjectsNumber;
	private long EXPIRATION_TIME = 20000;// 20s
	private Hashtable<T, Long> mActiveObjcets, mInactiveObjects;
	private Queue<WeakReference<T>> mQueue;
	@Override
	public final void createPool(int max) {
		if (DEBUG) {
			Log.d(TAG, "createPool size:" + max);
		}
		sMaxObjectsNumber = max;
		mActiveObjcets = new Hashtable<T, Long>(max);
		mInactiveObjects = new Hashtable<T, Long>(max);
		mQueue = new LinkedList<WeakReference<T>>();
	}
	
	@Override
	public synchronized final T allocate() {
		if (DEBUG) {
			Log.d(TAG, "allocate");
		}
		long now = System.currentTimeMillis();
		T t;
		if (mInactiveObjects.size() > 0) {
			Enumeration<T> e = mInactiveObjects.keys();
			while (e.hasMoreElements()) {
				t = e.nextElement();
				mInactiveObjects.remove(t);
				mActiveObjcets.put(t, now);
				return (t);
			}
		}
		t = getObjectFromQueue();
		if (t != null) {
			return t;
		}
		t = createObject();
		mActiveObjcets.put(t, now);
		return (t);
	}

	private final T getObjectFromQueue() {
		T b;
		for (int i = 0; i < mQueue.size(); i++) {
			b = mQueue.poll().get();
			if (b != null) {
				if (DEBUG) {
					Log.d(TAG, "getObjectFromQueue suc");
				}
				return b;
			}
		}
		if (DEBUG) {
			Log.d(TAG, "getObjectFromQueue failed!");
		}
		return null;
	}

	@Override
	public synchronized final void deallocate(T t) {
		long now = System.currentTimeMillis();
		mActiveObjcets.remove(t);
		if (upToLimit()) {
			if (DEBUG) {
				Log.d(TAG, "deallocate upToLimit!");
			}
			addToQueue(t);
			t = null;
		} else {
			if (DEBUG) {
				Log.d(TAG, "deallocate suc");
			}
			mInactiveObjects.put(t, now);
		}
	}

	/**
	 * 判断是否到达上限值
	 * 
	 * @return true：达到上限 ，false:没有达到上限
	 */
	protected abstract boolean upToLimit();

	@Override
	public void addToQueue(T t) {
		if (DEBUG) {
			Log.d(TAG, "addToQueue");
		}
		mQueue.add(new WeakReference<T>(t));
	}

	@Override
	public final int getActiveObjectsSize() {
		return mActiveObjcets.size();
	}

	@Override
	public final int getInactiveObjectsSize() {
		return mInactiveObjects.size();
	}

	@Override
	public final int getPoolSize() {
		return mActiveObjcets.size() + mInactiveObjects.size();
	}

	@Override
	public synchronized final void cleanUp() {
		if (DEBUG) {
			Log.d(TAG, "cleanUp");
		}
		T o;
		long now = System.currentTimeMillis();
		Enumeration<T> keys = mInactiveObjects.keys();
		while (keys.hasMoreElements()) {
			o = keys.nextElement();
			if ((now - ((Long) mInactiveObjects.get(o)).longValue()) > EXPIRATION_TIME) {
				mInactiveObjects.remove(o);
				o = null;
			}
		}
		System.gc();
	}

	@Override
	public final void release() {
		mActiveObjcets.clear();
		mInactiveObjects.clear();
		mQueue.clear();
	}

	@Override
	public String toString() {
		return this.getClass().getSimpleName() + "--当前活跃对象："
				+ mActiveObjcets.size() + ";非活跃对象：" + mInactiveObjects.size()+";暂存队列拥有对象："+mQueue.size();
	}
}
